//=========================================================================
// Copyright (C) 2024 The C++ Component Model(COMO) Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=========================================================================

// g++ -o test_TlsfYoungAgeString test_TlsfYoungAgeString.cpp ../tlsf/tlsf.c ../tlsf/TlsfStdString.cpp

#include <iostream>
#include <cassert>
#include <cstring>
#include "../tlsf/TlsfStdString.h"

using namespace como;

void on_allocation_failure() {
    std::cerr << "Memory allocation failed!" << std::endl;
    std::abort();
}

int main()
{
    // ------------------------

    size_t alloc_size = 2642080;
    size_t size = alloc_size + tlsf_size() + tlsf_pool_overhead() + tlsf_alloc_overhead();

    void* memory = ::malloc(size);

    tlsf_t tlsf = tlsf_create_with_pool(memory, size);
    tlsf_walk_pool(tlsf_get_pool(tlsf), 0, 0);

    std::cout << "try alloc " << std::hex << alloc_size << std::endl;
    void* ptr = tlsf_malloc(tlsf, 100);
    assert(ptr);
    std::cout << "tlsf_malloc: " << std::hex << ptr << std::endl;

    ptr = tlsf_free(tlsf, ptr);
    std::cout << "tlsf_free  : " << std::hex << ptr << std::endl;

    ptr = tlsf_malloc(tlsf, 100);
    assert(ptr);
    std::cout << "tlsf_malloc: " << std::hex << ptr << std::endl;

    ptr = tlsf_malloc(tlsf, 100);
    assert(ptr);
    std::cout << "tlsf_malloc: " << std::hex << ptr << std::endl;

    tlsf_walk_pool(tlsf_get_pool(tlsf), 0, 0);

    ::free(memory);

    // ------------------------

    constexpr size_t pool_size = 1024 * 1024; // 1MB
    MemoryHolder memHolder(pool_size);
    memHolder.Set_OnFailture(on_allocation_failure);

    // 设置当前 TLSF 内存池
    set_current_memory_holder(&memHolder);

    // 保证堆内存分配的，来测试 TLSF 内存块复用的情况
    // 申请第一个字符串

    char buf[16384];
    strcpy(buf, "Hello TLSF ");
    for (int i = 0;  i < 100;  i++) {
        char buf2[64];

        sprintf(buf2, "Hello TLSF %d ", i);
        strcat(buf, buf2);
    }

    TlsfYoungAgeString str1((TlsfYoungAge *)buf);
    void* addr1 = static_cast<void*>(const_cast<TlsfYoungAge*>(str1.data()));
    std::cout << "Address of str1 data: " << addr1 << std::endl;

    std::cout << "-----------" << std::endl;
    tlsf_walk_pool(tlsf_get_pool(memHolder.mTlsf_memory_pool), 0, 0);
    // 释放 str1 内存
    str1.clear();
    str1.shrink_to_fit(); // 尽量释放内存回 TLSF

    std::cout << "-----------" << std::endl;
    tlsf_walk_pool(tlsf_get_pool(memHolder.mTlsf_memory_pool), 0, 0);
    // 再申请第二个字符串，大小与第一个字符串相同
    TlsfYoungAgeString str2((TlsfYoungAge *)buf);
    void* addr2 = static_cast<void*>(const_cast<TlsfYoungAge*>(str2.data()));
    std::cout << "Address of str2 data: " << addr2 << std::endl;

    if (addr1 == addr2) {
        std::cout << "Memory reused: addresses are the same." << std::endl;
    }
    else {
        std::cout << "Memory not reused: addresses are different." << std::endl;
    }

    std::cout << "-----------" << std::endl;
    tlsf_walk_pool(tlsf_get_pool(memHolder.mTlsf_memory_pool), 0, 0);
    return 0;
}
